#include "Database.h"

Database::Database(const char* filePath)
{
    fpath = filePath;
    string srcFile = "";
    string deCodeFile = "";
    readAllFile(srcFile, filePath);
    if (!srcFile.empty())
    {
        deCode(srcFile, deCodeFile);
        stringToPDatas(deCodeFile);
    }
}

Database::~Database()
{
    if (!datas.empty())
    {
        for (int i = 0; i < datas.size(); i++)
        {
            delete datas[i];
        }
    }
}
void Database::addPDataToString(string& str, PData& data)
{
    str.push_back('<');
    str.push_back((char)(data.icon >> 8));
    str.push_back((char)(data.icon));
    str += data.name;
    str.push_back('|');
    str += data.URL;
    str.push_back('|');
    str.push_back(data.cl);
    str.push_back('|');
    str += data.account;
    str.push_back('|');
    str += data.pwd;
    str.push_back('|');
    str += data.payPwd;
    str.push_back('|');
    str.push_back(data.secrecyLevel);
    str += data.note;
    str.push_back('|');
    for (int i = sizeof(data.time)/sizeof(char) - 1; i >= 0; i--)
    {
        str.push_back((char)(data.time >> (8*i)));
    }
    str.push_back('>');
    return;
}

void Database::addPData(PData& data)
{
    string strSrc;
    string strDst;
    PData* newData = new PData(data);
    datas.push_back(newData);
    for (int i = 0; i < datas.size(); i++)
    {
        addPDataToString(strSrc, *datas[i]);
    }
    getCode(strSrc, strDst);
    fstream fs;
    fs.open(fpath, std::ios::out|std::ios::binary);
    fs.write(&strDst[0], strDst.size());
    return;
}


void Database::getCode(std::string& src, std::string& dst)
{
    int num = 5;
    int size = src.size();
    srand((int)time(NULL));
    dst.reserve((size+4) * num);
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < num; j++)
        {
            if (j == i % num)
            {
                dst.push_back((~src[i])^0x55);
            }
            else
            {
                char temp = rand() % 254 - 127;
                dst.push_back(temp);
            }
        }
    }
    return;
}

void Database::deCode(std::string& src, std::string& dst)
{
    int count = 0;
    for (int i = 0; i < src.size(); )
    {
        dst.push_back(~(src[i] ^ 0x55));
        count++;
        i = count * 5 + count % 5;
    }
    return;
}

void Database::readAllFile(std::string& dst, const char* filePath)
{
    struct stat fileInfo;
    int res = stat(filePath, &fileInfo);
    if (0 != res)
    {
        std::fstream fs;
        fs.open(filePath, std::ios::out);
        fs.close();
        stat(filePath, &fileInfo);
    }
    std::fstream fs;
    int notRead = fileInfo.st_size;
    fs.open(filePath, std::ios::in|std::ios::binary);
    dst.reserve(notRead);
    const int readLen = 1024;
    char buf[readLen] = { 0 };
    while (notRead >= readLen)
    {
        fs.read(buf, readLen);
        dst.append(buf, readLen);
        notRead -= readLen;
    }
    fs.read(buf, notRead);
    dst.append(buf, notRead);
    fs.close();
    return;
}

void Database::stringToPDatas(string& str)
{
    int begin = 0;
    int end = 0;
    PData* data = nullptr;
    while (-1!= begin)
    {
        data = new PData;
        data->icon = (str[begin + 1] << 8) + (str[begin + 2]);
        begin += 3;
        end = str.find('|', begin);
        data->name.assign(str, begin, end - begin);
        begin = end + 1;
        end = str.find('|', begin);
        data->URL.assign(str, begin, end - begin);
        begin = end + 1;
        end = str.find('|', begin);
        switch (str[begin])
        {
        case 1:
            data->cl = other;
            break;
        case 2:
            data->cl = entertainment;
            break;
        case 3:
            data->cl = card;
            break;
        case 4:
            data->cl = learning;
            break;
        case 5:
            data->cl = APP;
            break;
        case 6:
            data->cl = tool;
            break;
        case 7:
            data->cl = commerce;
            break;
        case 8:
            data->cl = finace;
            break;
        }
        begin = end + 1;
        end = str.find('|', begin);
        data->account.assign(str, begin, end - begin);
        begin = end + 1;
        end = str.find('|', begin);
        data->pwd.assign(str, begin, end - begin);
        begin = end + 1;
        end = str.find('|', begin);
        data->payPwd.assign(str, begin, end - begin);
        begin = end + 1;
        data->secrecyLevel = str[begin];
        begin++;
        end = str.find('|', begin);
        data->note.assign(str, begin, end - begin);
        begin = end + 1;
        data->time = (str[begin] << 56) + (str[begin+1]<<48) + (str[begin+2]<<40) + (str[begin+3]<<32)+ (str[begin + 4] << 24)+ (str[begin + 5] << 16)+ (str[begin + 6] << 8)+ str[begin + 7];
        datas.push_back(data);
        begin = str.find('<', begin);
    }
}
//
//void Database::printDatas()
//{
//    if (!datas.empty())
//    {
//        for (int i = 0; i < datas.size(); i++)
//        {
//            cout << datas[i]->icon << '|' << datas[i]->name << '|' << datas[i]->URL << '|' << datas[i]->cl << '|' << datas[i]->account << '|' << datas[i]->pwd << '|' << datas[i]->payPwd
//                << '|' << datas[i]->secrecyLevel << '|' << datas[i]->note << '|' << datas[i]->time << '|' << endl;
//        }
//    }
//}